package server.core;

import server.*;
import server.util.Enumerator;

import javax.servlet.*;
import java.util.Enumeration;
import java.util.HashMap;


public final class StandardWrapper extends ContainerBase implements Wrapper, ServletConfig {
    public StandardWrapper() {
        pipeline.setBasic(new StandardWrapperValve());
    }
    //属性--------------------------------------------------------------------------------
    //容器信息
    private static final String info = "server.core.StandardWrapper/1.0";
    //要加载的Servlet类的全类名
    private String servletClass = null;
    private int debug = 0;
    //是否正在卸载Servlet实例
    private boolean unloading = false;
    //Servlet实例
    private Servlet instance = null;
    //当前时间戳大于available时Servlet可用
    private long available = 0L;
    //存放初始化参数
    private HashMap<String, String> parameters = new HashMap<>();
    //自身的外观类,用于传递给Servlet类的方法: void init(ServletConfig config) throws ServletException;
    private StandardWrapperFacade facade = new StandardWrapperFacade(this);

    //方法--------------------------------------------------------------------------------
    //获取打印名(StandardWrapper[父容器名:容器名])
    @Override
    protected String logName() {
        StringBuffer sb = new StringBuffer("StandardWrapper[");
        if (getParent() != null)
            sb.append(getParent().getName());
        else
            sb.append("null");
        sb.append(':');
        sb.append(getName());
        sb.append(']');
        return sb.toString();
    }

    //如果没有加载servlet类，则加载并创建其实例对象，并调用对象的init方法，之后将实例返回。否则直接返回已经创建好的实例
    public synchronized Servlet loadServlet() throws ServletException {
        if (instance != null)
            return instance;
        //未指定全类名,直接设置该wrapper的servlet类不可用
        if (servletClass == null) {
            unavailable(null);
            throw new ServletException("要加载的类的全类名为空{" + getName() + "}");
        }
        Loader loader = getLoader();
        //没有加载器
        if (loader == null) {
            unavailable(null);
            throw new ServletException("没有可用的加载器{" + getName() + "}");
        }
        ClassLoader classLoader = loader.getClassLoader();
        //加载器中没有类加载器
        if (classLoader == null) {
            unavailable(null);
            throw new ServletException("没有可用的类加载器{" + getName() + "}");
        }
        //获取Servlet类对象
        Class clazz = null;
        try {
            clazz = classLoader.loadClass(servletClass);
        } catch (ClassNotFoundException e) {
            unavailable(null);
            throw new ServletException("未找到全类名为{" + servletClass + "}的类");
        }
        if (clazz == null) {
            unavailable(null);
            throw new ServletException("未找到全类名为{" + servletClass + "}的类");
        }
        //实例化Servlet类
        Servlet servlet = null;
        try {
            servlet = (Servlet)clazz.newInstance();
        } catch (ClassCastException e) {
            unavailable(null);
            throw new ServletException("类{" + servletClass + "}不是Servlet类");
        } catch (Throwable t) {
            unavailable(null);
            throw new ServletException("实例化类{" + servletClass + "}出错");
        }
        //调用init方法
        try {
            servlet.init(facade);
        } catch (UnavailableException f) {
            unavailable(f);
            throw f;
        } catch (Throwable t) {
            throw new ServletException("初始化类{" + servletClass + "}出错");
        }
        return servlet;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        if (getParent() != null) {
            sb.append(getParent().toString());
            sb.append(".");
        }
        sb.append("StandardWrapper[");
        sb.append(getName());
        sb.append("]");
        return sb.toString();
    }

    //getter
    public int getDebug() {
        return debug;
    }

    //setter
    public void setDebug(int debug) {
        this.debug = debug;
    }


    //实现Wrapper接口--------------------------------------------------------------------------------

    //返回创建好的servlet实例(未创建好则使用类加载器加载实例类并创建好实例调用init方法)
    @Override
    public Servlet allocate() throws ServletException {
        if (debug >= 1)
            log("Allocating an instance");
        //正在卸载Servlet,不能返回实例
        if(unloading)
            throw new ServletException("Cannot allocate servlet because it is being unloaded");
        if (instance == null) {
            synchronized (this) {
                //两次判断，避免多次调用loadServlet
                if (instance == null) {
                    try {
                        instance = loadServlet();
                    } catch (ServletException e) {
                        throw e;
                    } catch (Throwable e) {
                        //任何异常都转为ServletException异常
                        throw new ServletException("Error allocating a servlet instance", e);
                    }
                }
            }
        }
        return instance;
    }

    //根据UnavailableException的内容设置available的时间
    @Override
    public void unavailable(UnavailableException unavailable) {
        log("Marking servlet {" + getName() + "} as unavailable");
        if (unavailable == null)
            setAvailable(Long.MAX_VALUE);
        else if (unavailable.isPermanent())
            setAvailable(Long.MAX_VALUE);
        else {
            int unavailableSeconds = unavailable.getUnavailableSeconds();
            if (unavailableSeconds <= 0)
                unavailableSeconds = 60;
            setAvailable(System.currentTimeMillis() + (unavailableSeconds * 1000L));
        }

    }

    @Override
    public void setAvailable(long available) {
        if (available > System.currentTimeMillis())
            this.available = available;
        else
            this.available = 0;
    }

    @Override
    public long getAvailable() {
        return available;
    }

    //获取要加载的Servlet类的全类名
    @Override
    public String getServletClass() {
        return servletClass;
    }

    //设置要加载的Servlet类的全类名
    @Override
    public void setServletClass(String servletClass) {
        this.servletClass = servletClass;
    }

    //根据name返回对应的初始化参数
    @Override
    public String findInitParameter(String name) {
        synchronized (parameters) {
            return parameters.get(name);
        }
    }

    @Override
    public String[] findInitParameters() {
        synchronized (parameters) {
            String[] strings = new String[parameters.size()];
            return parameters.keySet().toArray(strings);
        }
    }

    //添加初始化参数
    @Override
    public void addInitParameter(String name, String value) {
        synchronized (parameters) {
            parameters.put(name, value);
        }
    }

    //根据name删除初始化参数
    @Override
    public void removeInitParameter(String name) {
        synchronized (parameters) {
            parameters.remove(name);
        }
    }

    //当前servlet是否不可用
    @Override
    public boolean isUnavailable() {
        if (available == 0)
            return false;
        if (System.currentTimeMillis() >= available) {
            available = 0;
            return false;
        }
        return true;
    }

    //卸载Servlet实例,设置instance为空
    @Override
    public void unload() throws ServletException {
        //实例为空,不用卸载
        if (instance == null)
            return;
        //正在卸载
        unloading = true;
        try {
            //调用实例的destory方法
            instance.destroy();
        } catch (Throwable t) {
            instance = null;
            unloading = false;
            throw new ServletException("Servlet.destroy() for servlet {" + getName() + "} threw exception", t);
        }
        instance = null;
        unloading = false;
    }

    //实现Container接口--------------------------------------------------------------------------------
    //获取容器信息
    @Override
    public String getInfo() {
        return info;
    }

    //设置父容器(Wrapper的父容器只能是Context)
    @Override
    public void setParent(Container parent) {
        if (parent != null && !(parent instanceof Context)) {
            throw new IllegalArgumentException("Parent container of a Wrapper must be a Context");
        }
        super.setParent(parent);
    }

    //Wrapper容器不能添加子容器
    @Override
    public void addChild(Container child) {
        throw new IllegalStateException("Wrapper container may not have child containers");
    }

    //实现ServletConfig接口--------------------------------------------------------------------------------

    //返回容器名
    @Override
    public String getServletName() {
        return getName();
    }

    @Override
    public ServletContext getServletContext() {
        if (parent == null)
            return null;
        if (!(parent instanceof Context))
            return null;
        return ((Context)parent).getServletContext();
    }

    //根据name返回对应的初始化参数
    @Override
    public String getInitParameter(String name) {
        return findInitParameter(name);
    }

    //返回所有的的初始化参数名
    @Override
    public Enumeration<String> getInitParameterNames() {
        synchronized (parameters) {
            return new Enumerator<String>(parameters.keySet());
        }
    }

    //实现LifeCycle接口--------------------------------------------------------------------------------

    @Override
    public void start() throws LifecycleException {
        super.start();
    }

    @Override
    public void stop() throws LifecycleException {
        try {
            unload();
        } catch (ServletException e) {
            log("Servlet {" + getName() + "} threw unload() exception", e);
        }
        super.stop();
    }
}
